import type { Coord } from "./type";
import Vector from "./vector";

class Matrix {
  // 构造函数，接收一个二维数组作为参数
  constructor(private twoDimArrar: number[][]) {}

  /**
   * 返回矩阵的形状，即行数和列数
   * @returns 矩阵的形状，即行数和列数
   */
  shape() {
    return [this.twoDimArrar.length, this.twoDimArrar[0].length];
  }

  /**
   * 获取矩阵的行数
   */
  get rowNum() {
    return this.shape()[0];
  }

  /**
   * 获取矩阵的列数
   */
  get colNum() {
    return this.shape()[1];
  }

  /**
   * 获取矩阵的大小，即元素个数
   */
  get size() {
    return this.rowNum * this.colNum;
  }

  /**
   * 获取指定行的向量
   * @param index 指定行的索引
   * @returns
   */
  rowVector(index: number) {
    return new Vector(this.twoDimArrar[index]);
  }

  /**
   * 获取指定列的向量
   * @param index 指定列的索引
   * @returns
   */
  colVector(index: number) {
    return new Vector(this.twoDimArrar.map((row) => row[index]));
  }

  /**
   * 获取指定位置的元素
   * @param position 指定位置的坐标
   * @returns
   */
  getItem(position: Coord) {
    return this.twoDimArrar[position[0]][position[1]];
  }

  /**
   * 矩阵相加
   * @param another 另一个矩阵
   * @returns
   */
  add(another: Matrix) {
    // 如果两个矩阵的大小或行数不匹配，则抛出错误
    if (this.size !== another.size || this.rowNum !== another.rowNum) {
      throw new Error("Matrix size not match");
    }
    const finalList: number[][] = [];
    // 遍历矩阵的每个元素，进行相加
    for (let i = 0; i < this.rowNum; i++) {
      const row: number[] = [];
      for (let j = 0; j < this.colNum; j++) {
        row.push(this.getItem([i, j]) + another.getItem([i, j]));
      }
      finalList.push(row);
    }
    // 返回新的矩阵
    return new Matrix(finalList);
  }

  /**
   * 矩阵相减
   * @param another 另一个矩阵
   * @returns
   */
  sub(another: Matrix) {
    // 如果两个矩阵的大小或行数不匹配，则抛出错误
    if (this.size !== another.size || this.rowNum !== another.rowNum) {
      throw new Error("Matrix size not match");
    }
    const finalList: number[][] = [];
    // 遍历矩阵的每个元素，进行相减
    for (let i = 0; i < this.rowNum; i++) {
      const row: number[] = [];
      for (let j = 0; j < this.colNum; j++) {
        row.push(this.getItem([i, j]) - another.getItem([i, j]));
      }
      finalList.push(row);
    }
    // 返回新的矩阵
    return new Matrix(finalList);
  }

  /**
   * 矩阵乘以一个数
   * @param k 一个数
   * @returns
   */
  mul(k: number) {
    const finalList: number[][] = [];
    // 遍历矩阵的每个元素，进行乘法
    for (let i = 0; i < this.rowNum; i++) {
      const row: number[] = [];
      for (let j = 0; j < this.colNum; j++) {
        row.push(this.getItem([i, j]) * k);
      }
      finalList.push(row);
    }
    // 返回新的矩阵
    return new Matrix(finalList);
  }

  /**
   * 矩阵除以一个数
   * @param k 一个数
   * @returns
   */
  div(k: number) {
    if (k === 0) {
      throw new Error("Divided by zero");
    }
    return this.mul(1 / k);
  }

  /**
   * 矩阵乘以一个向量
   * @param vector 向量
   * @returns
   */
  mulVector(vector: Vector) {
    if (this.colNum !== vector.length) {
      throw new Error("Matrix cloumn number not match vector length");
    }
    const finalList: number[] = [];
    for (let i = 0; i < this.rowNum; i++) {
      finalList.push(this.rowVector(i).dotMul(vector));
    }
    return new Vector(finalList);
  }

  /**
   * 矩阵乘以另一个矩阵
   * @param another 另一个矩阵
   * @returns
   */
  mulMatrix(another: Matrix) {
    if (this.colNum !== another.rowNum) {
      throw new Error("Matrix cloumn number not match another row number");
    }
    const finalList: number[][] = [];
    for (let i = 0; i < this.rowNum; i++) {
      const resultList: number[] = [];
      const rowVector = this.rowVector(i);
      for (let j = 0; j < another.colNum; j++) {
        const colVector = another.colVector(j);
        resultList.push(rowVector.dotMul(colVector));
      }
      finalList.push(resultList);
    }
    return new Matrix(finalList);
  }
}

export default Matrix;
